package com.czapl.drawing;

import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.g2d.Sprite;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.scenes.scene2d.Actor;
import com.badlogic.gdx.scenes.scene2d.Touchable;
import com.badlogic.gdx.utils.Array;
import com.czapl.api.ITower;
import com.czapl.api.IUnit;
import com.czapl.mygdxgame.MainScreen;

public abstract class CTower extends Actor implements ITower {
	protected AnimatedSprite m_animatedSprite;
	protected Sprite m_staticSprite = null;
	protected Sprite m_cannonSprite = null;
	private IUnit m_unitAimed = null;
	private boolean m_isAimed = false;
	private float m_cannonDesiredRotation = 0;
	private float m_cannonCurrentRotation = 0;
	private float m_reloadTimer = 0;
	
	protected float m_range;
	protected float m_fireRate;
	protected float m_rotationSpeed;
	protected Vector2 m_position = new Vector2(0,0);

	public CTower() {
		
	}

	public CTower(CTower instance) {
		//TODO magic values
		setTouchable(Touchable.disabled);
		setSize(32,32);
		m_cannonSprite = instance.m_cannonSprite;
		m_animatedSprite = instance.m_animatedSprite;
		m_staticSprite = instance.m_staticSprite;
		m_range = instance.m_range;
		m_fireRate = instance.m_fireRate;
		m_rotationSpeed = instance.m_rotationSpeed;
		if(m_animatedSprite != null) {
			m_animatedSprite.setAnimationRate(1);
			m_animatedSprite.play();
		}
		if(m_cannonSprite == null) {
			m_isAimed = true;
		}
	}
	
	abstract public CTower clone();
	
	@Override
	public float getRotationSpeed() {
		return m_rotationSpeed;
	}

	@Override
	public void setRotationSpeed(float m_rotationSpeed) {
		this.m_rotationSpeed = m_rotationSpeed;
	}
	
	@Override
	public void setPosition(float x, float y) {
		m_position.x = x+getWidth()/2;
		m_position.y = y+getHeight()/2;
		setX(x);
		setY(y);
	}
	
	@Override
	public boolean isUnitInRange(IUnit unit) {
		Vector2 unitPosition = unit.getPosition();
		//circle equation
		return (unitPosition.x - m_position.x)*(unitPosition.x - m_position.x) 
				+ (unitPosition.y - m_position.y)*(unitPosition.y - m_position.y) < m_range*m_range;
	}
	
	private void updateRotation() {
		float xDistance = (m_unitAimed.getPosition().x-m_position.x);
		float yDistance = (m_unitAimed.getPosition().y-m_position.y);
		float diffCW = 0;
		float diffCCW = 0;
		
		m_cannonDesiredRotation = (float) ( (Math.atan2(yDistance,xDistance)+Math.PI)*180/Math.PI );
		float rotationDiff = m_cannonDesiredRotation-m_cannonCurrentRotation;
		
		if(rotationDiff > 0) {
			diffCW = 360-rotationDiff;
			diffCCW = rotationDiff;
		}
		else {
			diffCCW = 360+rotationDiff;
			diffCW = -rotationDiff;
		}
		
		//System.out.println("CW="+(int)diffCW +" CCW="+(int)diffCCW);
		if(diffCCW < diffCW) {
			//rotate CCW
			if(diffCCW == 0) {
				//System.out.println("noo need to rotate CCW");
				m_isAimed = true;
				return; //no need to rotate
			}
			if(diffCCW > m_rotationSpeed) {
				m_cannonCurrentRotation  += m_rotationSpeed;
				m_isAimed = false;
			}
			else {
				m_cannonCurrentRotation  += diffCCW;
				m_isAimed = true;
			}
		}
		else {
			//rotate CW
			if(diffCW == 0) {
				//System.out.println("noo need to rotate CCW");
				m_isAimed = true;
				return; //no need to rotate
			}
			if(diffCW > m_rotationSpeed) {
				m_cannonCurrentRotation  -= m_rotationSpeed;
				m_isAimed = false;
			}
			else {
				m_cannonCurrentRotation  -= diffCW;
				m_isAimed = true;
			}
		}
		if(m_cannonCurrentRotation < 0) {
			m_cannonCurrentRotation +=360;
		}
		if(m_cannonCurrentRotation > 360) {
			m_cannonCurrentRotation -=360;
		}
	}
	
	@Override
	public void act (float delta) {
		super.act(delta);
		aimNextUnit(MainScreen.getGameBoard().getUnits());
		if(m_unitAimed != null) {

			if(m_cannonSprite != null) {
				updateRotation();
			}
		
			if(m_isAimed) {
				//System.out.println("unit aimed");
				if(m_reloadTimer >= m_fireRate ) {
					m_reloadTimer = 0;
					launchProjectile(m_unitAimed);
				}
				m_reloadTimer++;
				
			}
		}
		

		//System.out.println("a="+m_cannonDesiredRotation +" d="+m_cannonCurrentRotation);
		if(m_animatedSprite != null) {
			m_animatedSprite.update(delta);
		}
	}
	
	abstract protected void launchProjectile(IUnit unit);

	@Override
	public void draw (SpriteBatch batch, float parentAlpha) {
        Color color = getColor();
        batch.setProjectionMatrix(getStage().getCamera().combined);
        batch.setColor(color.r, color.g, color.b, color.a * parentAlpha);
        if(m_animatedSprite != null) {
        	batch.draw(m_animatedSprite, getX(), getY(), getOriginX(), getOriginY(),
                getWidth(), getHeight(), getScaleX(), getScaleY(), 0);
        }
        else {
        	batch.draw(m_staticSprite, getX(), getY(), getOriginX(), getOriginY(),
                    getWidth(), getHeight(), getScaleX(), getScaleY(), 0);
        }
        if(m_cannonSprite != null) {
        	batch.draw(m_cannonSprite, getX(), getY(), getOriginX()+16, getOriginY()+16,
        		getWidth(), getHeight(), getScaleX(), getScaleY(), m_cannonCurrentRotation );
        }
//        for(IProjectile projectile : m_projectiles) {
//        	Sprite projectileSprite = (Sprite) projectile;
//        	batch.draw(projectileSprite, projectileSprite.getX(), projectileSprite.getY(),
//        			projectileSprite.getOriginX(), projectileSprite.getOriginY(),
//        			projectileSprite.getWidth(), projectileSprite.getHeight(),
//        			projectileSprite.getScaleX(), projectileSprite.getScaleY(), projectileSprite.getRotation());
//        }
	}

	@Override
	public float getRange() {
		return m_range;
	}

	@Override
	public void setAimedUnit(IUnit unit) {
		m_unitAimed = unit;
	}
	
	@Override
	public IUnit getAimedUnit() {
		return m_unitAimed;
		
	}

	@Override
	public Vector2 getPosition() {
		return m_position.cpy();
	}
	
	@Override
	public void aimNextUnit(Array<IUnit> units) {
		if(getAimedUnit() == null) {
			for(IUnit unit: units) {
				if(isUnitInRange(unit)) {
					setAimedUnit(unit);
				}
			}
		}
		else {
			//check if the aimed unit has not been removed yet
			if(!units.contains(getAimedUnit(), true)) {
				setAimedUnit(null);
				return;
			}
			if(!isUnitInRange(getAimedUnit())) {
				for(IUnit unit: units) {
					if(isUnitInRange(unit)) {
						setAimedUnit(unit);
					}
				}
				if(!isUnitInRange(getAimedUnit())) {
					setAimedUnit(null);
				}
			}
		}
		
	}
	
	
}
